import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import matplotlib.dates as mdates
import os
from scipy.interpolate import make_interp_spline
from datetime import datetime

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# 定义常量 - 保存结果的目录
RESULTS_DIR = r"D:\大三上\大数据分析及数据可视化\《Excel数据可视化 - 从图表到数据大屏》-清华-郭宏远\实验\results"


def load_erp_data():
    """加载ERP订单数据"""
    # 定义可能的文件路径
    possible_paths = [
        r"D:\大三上\大数据分析及数据可视化\《Excel数据可视化 - 从图表到数据大屏》-清华-郭宏远\实验\data\erp_order_data.xlsx",
        r"D:\大三上\大数据分析及数据可视化\《Excel数据可视化 - 从图表到数据大屏》-清华-郭宏远\实验\erp_order_data.xlsx"
    ]

    for path in possible_paths:
        if os.path.exists(path):
            try:
                df = pd.read_excel(path)
                # 确保日期格式正确
                if 'order_time' in df.columns:
                    df['order_time'] = pd.to_datetime(df['order_time'])
                print(f"✓ 数据加载成功: {path}")
                return df
            except Exception as e:
                print(f"读取 {path} 失败: {e}")
                continue

    raise FileNotFoundError("未找到erp_order_data.xlsx文件，请确认文件是否存在或路径是否正确")


def process_monthly_sales(df):
    """处理月度销售数据"""
    # 确保order_time是datetime类型
    if 'order_time' not in df.columns:
        raise ValueError("数据中缺少'order_time'列，无法进行时间分析")

    # 确保product_amount列存在
    if 'product_amount' not in df.columns:
        raise ValueError("数据中缺少'product_amount'列，无法计算销售金额")

    # 创建副本防止修改原始数据
    df = df.copy()

    # 提取年份和月份
    df['year'] = df['order_time'].dt.year
    df['month'] = df['order_time'].dt.month

    # 按年月分组汇总销量
    monthly_sales = df.groupby(['year', 'month'])['product_amount'].sum().reset_index()

    # 创建月份标签
    monthly_sales['month_label'] = monthly_sales['month'].apply(lambda x: f"{x}月")

    # 按时间顺序排序
    monthly_sales = monthly_sales.sort_values(by=['year', 'month'])

    # 创建X轴数据（月份位置）
    months = monthly_sales['month'].tolist()
    years = monthly_sales['year'].tolist()
    sales = monthly_sales['product_amount'].tolist()

    # 生成月份序列（5月到3月）
    month_sequence = ['5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月']

    # 识别最高销量点
    max_sales = max(sales) if sales else 0
    max_index = sales.index(max_sales) if sales else 0
    max_month = months[max_index] if months else 0
    max_year = years[max_index] if years else 0

    return monthly_sales, months, years, sales, max_sales, max_month, max_year, month_sequence


def create_smooth_line_chart():
    """创建平滑折线图：化妆品品类月度销量走势"""
    # 加载数据
    df = load_erp_data()

    # 处理月度销售数据
    monthly_sales, months, years, sales, max_sales, max_month, max_year, month_sequence = process_monthly_sales(df)

    # 创建图形 - 深色背景
    fig, ax = plt.subplots(figsize=(14, 9), facecolor='#1A1A2E')
    ax.set_facecolor('#1A1A2E')

    # 创建X轴位置
    x_pos = np.arange(len(month_sequence))

    # 创建平滑曲线
    if len(sales) > 3:
        # 使用样条插值创建平滑曲线
        x = np.arange(len(sales))
        y = np.array(sales)

        # 创建更密集的X轴点
        x_new = np.linspace(0, len(sales) - 1, 300)

        # 创建平滑曲线
        spl = make_interp_spline(x, y, k=3)
        y_smooth = spl(x_new)

        # 找到最高点
        max_index = np.argmax(y_smooth)
        max_y = y_smooth[max_index]
        max_x = x_new[max_index]
    else:
        # 如果数据不足，使用原始数据
        x_new = np.arange(len(sales))
        y_smooth = np.array(sales)
        max_index = np.argmax(y_smooth)
        max_y = y_smooth[max_index]
        max_x = x_new[max_index]

    # 绘制平滑折线
    line, = ax.plot(x_new, y_smooth, color='#FF6B6B', linewidth=3)

    # 添加最高点标记
    ax.plot([max_x], [max_y], 'o', color='white', markersize=10, markeredgecolor='#FF6B6B', markeredgewidth=2)

    # 添加垂直虚线到X轴
    ax.axvline(x=max_x, color='white', linestyle='--', alpha=0.5)

    # 添加最高点标签
    ax.text(max_x, max_y + 100, f'{int(max_y)}',
            ha='center', va='bottom', fontsize=12, fontweight='bold', color='white',
            bbox=dict(boxstyle='round,pad=0.3', facecolor='#2C3E50', edgecolor='none', alpha=0.7))

    # 设置X轴
    ax.set_xticks(np.arange(len(month_sequence)))
    ax.set_xticklabels(month_sequence, color='#E0E0E0', fontsize=12)
    ax.set_xlabel('', fontsize=14, color='#E0E0E0')

    # 设置Y轴
    ax.set_yticks([0, 1000, 2000, 3000, 4000])
    ax.set_yticklabels([0, 1000, 2000, 3000, 4000], color='#E0E0E0', fontsize=12)
    ax.set_ylabel('销量', fontsize=14, color='#E0E0E0')

    # 设置标题
    title_main = '化妆品品类月度销量走势'
    title_sub = f'{max_year}年销量迅速增加，{max_month}月最高，销量达到{int(max_y)}'

    ax.set_title(f'{title_main}\n{title_sub}',
                 fontsize=20, fontweight='bold', pad=25, color='#FFFFFF')

    # 美化坐标轴
    for spine in ax.spines.values():
        spine.set_color('#4A4A6A')
        spine.set_linewidth(2)

    # 设置网格线
    ax.grid(axis='y', linestyle='--', alpha=0.3, color='#4A4A6A')
    ax.set_axisbelow(True)

    # 设置Y轴范围
    max_value = max(y_smooth) * 1.15
    ax.set_ylim(0, max_value)

    # 添加2021年和2022年标签区域
    ax.axhline(y=-150, xmin=0, xmax=0.7, color='#4BB5C2', linewidth=30)
    ax.axhline(y=-150, xmin=0.7, xmax=1, color='#E56A72', linewidth=30)

    # 添加年份标签
    ax.text(0.35, -150, '2021', ha='center', va='center', transform=ax.transData,
            fontsize=14, fontweight='bold', color='white')
    ax.text(0.85, -150, '2022', ha='center', va='center', transform=ax.transData,
            fontsize=14, fontweight='bold', color='white')

    # 添加数据来源
    latest_date = df['order_time'].max()
    latest_date_str = latest_date.strftime('%Y.%m.%d')
    source_text = f'*注：数据来源于公司销售系统，统计日期截至{latest_date_str}'
    ax.text(0.02, 0.02, source_text, transform=ax.transAxes,
            fontsize=10, color='#B0B0B0', alpha=0.7, va='bottom')

    # 调整布局
    plt.tight_layout()

    # 确保结果目录存在
    os.makedirs(RESULTS_DIR, exist_ok=True)
    # 保存图片
    output_path = os.path.join(RESULTS_DIR, '11_平滑折线图.png')
    plt.savefig(output_path, dpi=300, bbox_inches='tight',
                facecolor='#1A1A2E', edgecolor='none')

    plt.show()

    # 数据分析
    print("平滑折线图数据分析：")
    print(f"- 数据覆盖时间：{min(years)}年{min(months)}月 - {max(years)}年{max(months)}月")
    print(f"- 最高销量：{int(max_y)}，出现在{max_year}年{max_month}月")

    return fig, ax


# 执行代码
if __name__ == "__main__":
    try:
        fig, ax = create_smooth_line_chart()
    except Exception as e:
        print(f"图表生成失败: {e}")
        raise